package me.stone.stanimeclient.core.common.di

import android.content.ClipboardManager
import android.content.Context
import android.net.ConnectivityManager
import android.net.wifi.WifiManager
import android.os.Handler
import android.os.Looper
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Runnable
import kotlinx.coroutines.SupervisorJob
import java.util.concurrent.Executor
import java.util.concurrent.Executors
import javax.inject.Inject
import javax.inject.Singleton


@Module
@InstallIn(SingletonComponent::class)
object CoroutinesModule {

    @DefaultDispatcher
    @Provides
    fun providesDefaultDispatcher(): CoroutineDispatcher = Dispatchers.Default

    @IoDispatcher
    @Provides
    fun providesIoDispatcher(): CoroutineDispatcher = Dispatchers.IO

    @MainDispatcher
    @Provides
    fun providesMainDispatcher(): CoroutineDispatcher = Dispatchers.Main

    @MainImmediateDispatcher
    @Provides
    fun providesMainImmediateDispatcher(): CoroutineDispatcher = Dispatchers.Main.immediate

}


@Module
@InstallIn(SingletonComponent::class)
object AppModules {

    @Provides
    fun provideWifiManager(@ApplicationContext context: Context): WifiManager =
        context.applicationContext.getSystemService(Context.WIFI_SERVICE)
                as WifiManager

    @Provides
    fun provideConnectivityManager(@ApplicationContext context: Context): ConnectivityManager =
        context.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE)
                as ConnectivityManager

    @Provides
    fun provideClipboardManager(@ApplicationContext context: Context): ClipboardManager =
        context.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE)
                as ClipboardManager

    @Singleton
    @Provides
    @MainThreadHandler
    fun providesMainThreadHandler(): AppHandler = AppMainHandler()

    @Provides
    @ApplicationScope
    fun providesApplicationScope(
        @DefaultDispatcher defaultDispatcher: CoroutineDispatcher
    ): CoroutineScope = CoroutineScope(SupervisorJob() + defaultDispatcher)

}


@Module
@InstallIn(SingletonComponent::class)
object ExecutorsModule {

    @Provides
    @NetworkExecutor
    fun providesNetworkExecutor(): Executor = Executors.newFixedThreadPool(4)

    @Provides
    @DiskExecutor
    fun providesDiskExecutor(): Executor = Executors.newFixedThreadPool(4)

    @Provides
    @MainExecutor
    fun providesMainExecutor(
        @MainThreadHandler handler: AppHandler
    ): Executor = AppMainThreadExecutor(handler)

}


interface AppHandler {

    fun post(runnable: Runnable)

    fun postDelay(runnable: Runnable, millisDelay: Long)

    fun removeCallbacks(runnable: Runnable)

}

class AppMainHandler: AppHandler {

    private val mHandler = Handler(Looper.getMainLooper())

    override fun post(runnable: Runnable) {
        mHandler.post(runnable)
    }

    override fun postDelay(runnable: Runnable, millisDelay: Long) {
        mHandler.postDelayed(runnable, millisDelay)
    }

    override fun removeCallbacks(runnable: Runnable) {
        mHandler.removeCallbacks(runnable)
    }

}

class AppMainThreadExecutor @Inject constructor(
    @MainThreadHandler val mMainHandler: AppHandler
): Executor {
    override fun execute(command: Runnable) {
        mMainHandler.post(command)
    }
}